package com.b2c.ftysys.dao.impl;

import java.math.BigInteger;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;

import com.b2c.ftysys.dao.DatabaseException;
import com.b2c.ftysys.dao.IDBUtils;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.b2c.ftysys.domain.BaseExample;
import com.b2c.ftysys.domain.PageResult;

@SuppressWarnings("unchecked")
public class SupportDAO<T> extends SqlMapClientDaoSupport implements
		IDBUtils<T> {

	/**
	 * 自增Id sqlMapId 置于b2c_fsy_staff_sqlMap.xml中
	 */
	public final static String SELECT_TABLE_STATUS = "b2c_fsy_staff.select_table_status";
	
	/**
	 * 自增Id 字段
	 */
	public final static String AUTO_INCREMENT_CODE = "Auto_increment";
	
	@Resource(name = "sqlMapClient")
	private SqlMapClient sqlMapClient;

	@PostConstruct
	public void initSqlMapClient() {
		super.setSqlMapClient(sqlMapClient);
	}

	public SqlMapClient getSqlClient() {
		return this.getSqlMapClient();
	}

	public int delete(T param, String statementName) throws DatabaseException {
		try {
			return getSqlMapClientTemplate().delete(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("delete object:" + param.getClass()
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public int deleteByObject(Object param, String statementName)
			throws DatabaseException {
		try {
			return getSqlMapClientTemplate().delete(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("delete object:" + param.getClass()
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public List<T> getList(String statementName) throws DatabaseException {
		try {
			return getSqlMapClientTemplate().queryForList(statementName);
		} catch (DataAccessException e) {
			throw new DatabaseException("query for list "
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public List<T> getList(Object param, String statementName)
			throws DatabaseException {
		try {
			return getSqlMapClientTemplate().queryForList(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with object:" + param.getClass()
					+ " for list mapped by sql statement:" + statementName
					+ " fail!", e);
		}
	}

	public PageResult getListByPage(PageResult page) throws DatabaseException {
		if (page == null)
			throw new DatabaseException("page parameter can not be null!");
		else if (null == page.getCountMappedId()
				|| null == page.getSelectDataMappedId())
			throw new DatabaseException("Mapped Id can not be null!");
		try {
			page.setRowCnt(this.getCountForPage(page.getSqlParamObj(),
					page.getCountMappedId()));

			if (page.getSqlParamObj() instanceof BaseExample) {
				BaseExample example = (BaseExample) page.getSqlParamObj();
				example.setPageSize(page.getPageSize());
				example.setStartLine(page.getStartRow());
				page.setSqlParamObj(example);
			}
			page.setPageList(this.getList(page.getSqlParamObj(),
					page.getSelectDataMappedId()));
			return page;
		} catch (DatabaseException e) {
			e.printStackTrace();
			throw new DatabaseException("查询数据分页列表时发生错误，错误map id["
					+ page.getCountMappedId() + "]", e);
		}
	}

	public List<T> getListPage(Object param, String statementName, int offset,
			int pageSize) throws DatabaseException {
		try {
			return getSqlMapClientTemplate().queryForList(statementName, param,
					offset, pageSize);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with object:" + param.getClass()
					+ "and page offset->" + offset + ",pageSize->" + pageSize
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public Map<String, T> getMap(String statementName, Object param,
			String keyProp) throws DatabaseException {
		try {
			return getSqlMapClientTemplate().queryForMap(statementName, param,
					keyProp);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with object:" + param.getClass()
					+ " for map mapped by sql statement:" + statementName
					+ " fail!", e);
		}
	}

	public T getObject(Object param, String statementName)
			throws DatabaseException {
		try {
			return (T) getSqlMapClientTemplate().queryForObject(statementName,
					param);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with object:" + param.getClass()
					+ " for object mapped by sql statement:" + statementName
					+ " fail!", e);
		}
	}

	public T getObject(Object param, String statementName, T resultObject)
			throws DatabaseException {
		try {
			return (T) getSqlMapClientTemplate().queryForObject(statementName,
					param, resultObject);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with object:" + param.getClass()
					+ " for object(" + resultObject.getClass()
					+ ") mapped by sql statement:" + statementName + " fail!",
					e);
		}
	}

	public T getObject(String statementName) throws DatabaseException {
		try {
			return (T) getSqlMapClientTemplate().queryForObject(statementName);
		} catch (DataAccessException e) {
			throw new DatabaseException(
					"query for object mapped by sql statement:" + statementName
							+ " fail!", e);
		}
	}

	public int save(T param, String statementName) throws DatabaseException {
		try {
			getSqlMapClientTemplate().insert(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("save object:" + param.getClass()
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
		return 0;
	}

	public int update(T param, String statementName) throws DatabaseException {
		try {
			return getSqlMapClientTemplate().update(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("update object:" + param.getClass()
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public int updateByObject(Object param, String statementName)
			throws DatabaseException {
		try {
			return getSqlMapClientTemplate().update(statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("update object:" + param.getClass()
					+ " mapped by sql statement:" + statementName + " fail!", e);
		}
	}

	public T queryWithId(Object id, String statementName)
			throws DatabaseException {
		try {
			return (T) getSqlMapClientTemplate().queryForObject(statementName,
					id);
		} catch (DataAccessException e) {
			throw new DatabaseException("query with id:" + id
					+ "for object mapped by sql statement:" + statementName
					+ " fail!", e);
		}
	}

	public int getCountForPage(Object param, String statementName)
			throws DatabaseException {
		try {
			return (Integer) getSqlMapClientTemplate().queryForObject(
					statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("count with object:" + param.getClass()
					+ " for counter mapped by sql statement:" + statementName
					+ " fail!", e);
		}
	}

	public int getCountByObjectForPage(Object param, String statementName)
			throws DatabaseException {
		try {
			return (Integer) getSqlMapClientTemplate().queryForObject(
					statementName, param);
		} catch (DataAccessException e) {
			throw new DatabaseException("count with object:" + param.getClass()
					+ " for counter mapped by sql statement:" + statementName
					+ " fail!", e);
		}

	}

	public List<T> getListPage(String statementName, int offset, int pageSize)
			throws DatabaseException {
		try {
			return getSqlMapClientTemplate().queryForList(statementName,
					offset, pageSize);
		} catch (DataAccessException e) {
			throw new DatabaseException("query and page offset->" + offset
					+ ",pageSize->" + pageSize + " mapped by sql statement:"
					+ statementName + " fail!", e);
		}
	}
	
	public Long getAutoIncrementId(String tableName) throws DatabaseException {
		Map<String, Object> dataMap;
		try {
			dataMap = (Map<String, Object>)sqlMapClient.queryForObject(
					SELECT_TABLE_STATUS, tableName);
			Object id = dataMap.get(AUTO_INCREMENT_CODE);
			if (id instanceof Long)
				return (Long) id;
			else if (id instanceof BigInteger)
				return ((BigInteger)id).longValue();
			else if (id instanceof Integer)
				return Long.valueOf(((Integer)id));
			else
				return (long) 0;
		} catch (SQLException e) {
			e.printStackTrace();
			throw new DatabaseException("获取[" + tableName + "]表自增Id时发生错误!", e);
		}

	}

}
